﻿/*
	Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <sstream>

#include "ApplicationView.h"
#include "../utility/utility.h"
#include "../render/_Render.h"
#include "../render/ProgramCache.h"
#include "../base/EventMouse.h"
#include "../base/InputEventDispatcher.h"
#include "../base/Debuger.h"
#include "../utility/StringUtility.h"
#include "IProcessMsg.h"
#include "Application.h"

namespace
{
	SkyEngine2d::ApplicationView* sg_app_view = nullptr;
}

namespace SkyEngine2d
{

	LRESULT CALLBACK mainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
		if (sg_app_view && sg_app_view->m_msgHandler)
		{
			return sg_app_view->m_msgHandler->processMsg(hwnd, msg, wParam, lParam);
		}

		return DefWindowProc(hwnd, msg, wParam, lParam);
	}

	bool ApplicationView::initWindows()
	{
		HINSTANCE hInstance = GetModuleHandle(NULL);

		WNDCLASS wc;
		wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
		wc.lpfnWndProc = mainWndProc;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = 0;
		wc.hInstance = hInstance;
		wc.hIcon = LoadIcon(0, IDI_APPLICATION);
		wc.hCursor = LoadCursor(0, IDC_ARROW);
		wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
		wc.lpszMenuName = 0;
		wc.lpszClassName = L"SkyGame";

		if (!RegisterClass(&wc))
		{
			return false;
		}

		RECT r = { 0, 0, (long)m_winSize.width, (long)m_winSize.height };
		AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
		int w = r.right - r.left;
		int h = r.bottom - r.top;

		m_wnd = CreateWindow(L"SkyGame", m_caption.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, w, h, 0, 0, hInstance, 0);

		if (!m_wnd)
		{
			return false;
		}

		ShowWindow(m_wnd, SW_SHOW);
		UpdateWindow(m_wnd);

		return true;
	}



	ApplicationView::ApplicationView()
		:IApplicationView()
		, m_wnd(nullptr)
		, m_caption(L"SGE2D")
		, m_winSize(1136, 640)
		, m_viewSize(1136, 640)
		, m_position(0, 0)
		, m_isInit(false)
		, m_desktopSize(0, 0)
	{
		//给全局变量赋值
		sg_app_view = this;
	}


	ApplicationView::~ApplicationView()
	{

	}

	bool ApplicationView::init(IProcessMsg* process_handler, const Size& win_size)
	{
		m_winSize = win_size;
		m_viewSize = win_size;
		//初始化处理
		DebugerAssert(process_handler, "处理消息的接口不能为NULL ");
		m_msgHandler = process_handler;
		//初始化桌面大小
		RECT desktop_rect;
		HWND hwnd_desktop = GetDesktopWindow();
		GetWindowRect(hwnd_desktop, &desktop_rect);
		m_desktopSize.width = desktop_rect.right - desktop_rect.left;
		m_desktopSize.height = desktop_rect.bottom - desktop_rect.top;
		//初始化窗口
		if (!this->initWindows())
		{
			return false;
		}
		//初始d3d接口
		m_render = std::make_unique<Render>();
		if (m_render && !m_render->init(m_wnd, m_viewSize.width, m_viewSize.height))
		{
			return false;
		}
		//初始化 默认 shander 
		ProgramCache::getInstance()->loadDefultPrograms(m_render->getD3dDevice());

		m_isInit = true;

		return  true;
	}

	void ApplicationView::calculateFrameStats(float frame_cnt)
	{
		float mspf = 1000.0f / frame_cnt;

		wchar_t t[256];
		swprintf_s(t, 256, L"%s  | Fps %.1f  | Mspf %.3f(ms)", m_caption.c_str(), frame_cnt, mspf);
		SetWindowText(m_wnd, t);
	}

	void ApplicationView::setCaption(const std::wstring& caption /*= L""*/)
	{
		m_caption = caption;

		if (m_isInit)
		{
			//更新 windows 的标题

			DebugerAssert(m_wnd, "win 句柄为 null ");

			SetWindowText(m_wnd, m_caption.c_str());
		}
	}

	const std::wstring& ApplicationView::getCaption()
	{
		return m_caption;
	}

	const Size& ApplicationView::getViewSize()
	{
		return m_viewSize;
	}


	SkyEngine2d::Render* ApplicationView::getRender() const
	{
		return m_render.get();
	}


	void ApplicationView::onResize(HWND hwnd, int w, int h)
	{
		if (m_render)
		{
			m_render->onResize(hwnd, w, h);
		}
	}

	const Size& ApplicationView::getWinSize()
	{
		return m_winSize;
	}


	void ApplicationView::setWinPosition(const Vector2& pos)
	{
		m_position = pos;
		if (m_isInit)
		{
			DebugerAssert(m_wnd, "win 句柄为 null ");

			MoveWindow(m_wnd, m_position.x, m_position.y, m_winSize.width, m_winSize.height, true);
		}
	}

	const Vector2& ApplicationView::getWinPosition()
	{
		return m_position;
	}

	const Size& ApplicationView::getDesktopSize()
	{
		return m_desktopSize;
	}
}
